if (!Client)
Client = {};

Client.feredataId = 0;
Client.feredataError = 0;
Client.feredataErrorMax = 5;

// Η μέθοδος "feredataError" χρησιμοποιείται σε περίπτωση αποτυχίας παραλαβής
// σκηνικών δεδομένων. Ως πρώτη παράμετρο δέχεται ένα μήνυμα σφάλματος το οποίο
// εμφανίζεται στο επάνω μέρος της σελίδας, ενώ μπορούν να ακολουθούν μηνύματα
// που εκτυπώνονται στο standard error. Αν κάποια παράμετρος είναι αριθμητική,
// τότε αυτή υποδηλώνει χρόνο σε milliseconds κατά τον οποίο θα γίνει εκ νέου
// απόπειρα παραλαβής πλήρων σκηνικών δεδομένων.
//
// Αν παρατηρηθούν πολλά διαδοχικά σφάλματα κατά την πραλαβή δεδομένων, τότε το
// πρόγραμμα σταματά.

Skiniko.prototype.feredataError = function() {
	var msg, i, delay;

	if (Client.feredataError++ > Client.feredataErrorMax) {
		msg = 'Διαδοχικά σφάλματα ενημέρωσης σκηνικού. Δοκιμάστε αργότερα…';

		if (ego.isDeveloper())
		throw msg;

		self.location = Selida.server + 'error?minima=' + msg.uri();
		return this;
	}

	msg = '';
	for (i = 1; i < Client.feredataError; i++)
	msg += '&bullet;';
	msg += arguments[0];
	Selida.fyi.epano(msg);

	// Διατρέχουμε τις υπόλοιπες παραμέτρους προκειμένου να εντοπίσουμε
	// τυχόν άλλα δεδομένα τα οποία θα εκτυπωθούν στο standard error,
	// ή χρονικά διαστήματα επανάληψης του αιτήματος.

	delay = null;
	for (i = 1; i < arguments.length; i++) {
		switch (typeof arguments[i]) {
		case 'number':
			delay = arguments[i];
			break;
		default:
			console.error(arguments[i]);
			break;
		}
	}

	// Αν εντοπίστηκε παράμετρος χρόνου, δρομολογούμε νέο αίτημα παραλαβής
	// πλήρων σκηνικών δεδομένων.

	if (delay)
	this.stisimo(delay);

	return this;
};

Skiniko.prototype.stisimo = function(delay) {
	var skiniko = this;

	if (delay) {
		setTimeout(function() {
			skiniko.stisimo();
		}, delay);
		return this;
	}

	Client.feredataId++;
	Selida.skiserService('skiniko', 'id=' + Client.feredataId).
	done(function(rsp) {
		var data;

		try {
			data = ('{' + rsp + '}').evalAsfales();;
		} catch (e) {
			return skiniko.feredataError('Παρελήφθησαν λανθασμένα σκηνικά δεδομένα', rsp, 1000);
		}

		if (!data.hasOwnProperty('id'))
		return skiniko.feredataError('Παρελήφθησαν σκηνικά δεδομένα χωρίς id', rsp, 1000);

		if (data.id < Client.feredataId)
		return skiniko.feredataError('Παρελήφθησαν παρωχημένα σκηνικά δεδομένα');

		skiniko.
		processFeredataFreska(data);
	}).
	fail(function(err) {
		Selida.skiserFail(err);
		skiniko.feredataError('Σφάλμα παραλαβής σκηνικών δεδομένων', 1000);
	});

	return this;
};

Skiniko.prototype.processFeredataFreska = function(data) {
	var skiniko = this;

	console.log('PROCESS FEREDATA FRESKA:', data);

	Arena.anazitisiAreaDOM.empty();
	Arena.thamonasAreaDOM.empty();
	Arena.kafenioAreaDOM.empty();
	Arena.trapeziAreaDOM.empty();
	Arena.sizitisiLobiDOM.empty();
	Arena.sizitisiKafenioDOM.empty();
	Arena.sizitisiPartidaDOM.empty();

	this.pektis = {};
	Globals.awalk(data.pektis, function(i, pektis) {
		skiniko.skinikoPektisSet(new Pektis(pektis));
	});

	ego.login = Selida.session.pektis;
	ego.pektis = skiniko.skinikoPektisGet(ego.login);
	if (!ego.pektis)
	return this.feredataError('Δεν βρέθηκε ο παίκτης στο σκηνικό', 1000);

	Globals.walk(data.peparam, function(login, plist) {
		var pektis;

		pektis = skiniko.skinikoPektisGet(login);
		if (!pektis)
		return;

		Globals.walk(plist, function(param, timi) {
			pektis.pektisPeparamSet(param, timi);
		});
	});

	Globals.walk(data.profinfo, function(login, plist) {
		var pektis;

		pektis = skiniko.skinikoPektisGet(login);
		if (!pektis)
		return;

		Globals.walk(plist, function(sxoliastis, kimeno) {
			pektis.pektisProfinfoSet(sxoliastis, kimeno);
		});
	});

	Globals.walk(data.sxesi, function(pektis, sxesi) {
		ego.pektis.pektisSxesiSet(pektis, sxesi);
	});

	this.kafenio = {};
	if (data.hasOwnProperty('kafenio'))
	Globals.awalk(data.kafenio, function(i, kafenio) {
		skiniko.skinikoKafenioSet(new Kafenio(kafenio));
	});

	if (data.hasOwnProperty('diapiste'))
	Globals.awalk(data.diapiste, function(i, diapiste) {
		skiniko.skinikoDiapisteSet(new Diapiste(diapiste));
	});

	this.trapezi = {};
	if (data.hasOwnProperty('trapezi'))
	Globals.awalk(data.trapezi, function(i, trapezi) {
		skiniko.skinikoTrapeziSet(new Trapezi(trapezi));
	});

	this.sinedria = {};
	Globals.awalk(data.sinedria, function(i, sinedria) {
		sinedria = new Sinedria(sinedria).
		sinedriaCreateDOM().
		sinedriaRefreshDOM();

		skiniko.skinikoSinedriaSet(sinedria);
		sinedria.sinedriaGetDOM().
		appendTo(Arena.thamonasAreaDOM);
	});

	ego.sinedria = skiniko.skinikoSinedriaGet(ego.login);
	if (!ego.sinedria)
	return this.feredataError('Δεν βρέθηκε η συνεδρία στο σκηνικό', 1000);

	if (data.hasOwnProperty('kafenio'))
	Globals.awalk(data.kafenio, function(i, kafenio) {
		kafenio = skiniko.skinikoKafenioGet(kafenio.kodikos);
		if (!kafenio)
		return;

		kafenio.
		kafenioCreateDOM().
		kafenioRefreshDOM();

		skiniko.skinikoKafenioSet(kafenio);
		kafenio.kafenioGetDOM().
		appendTo(Arena.kafenioAreaDOM);
	});

	if (Client.feredataError) {
		Selida.fyi.pano('Αποκαταστάθηκαν σφάλματα ενημέρωσης σκηνικού');
		Client.feredataError = 0;
	}

	this.
	egoRefreshDOM().
	panelRefresh().
	metavoles();

	return this;
};

Skiniko.prototype.metavoles = function() {
	var skiniko = this;

	Client.feredataId++;
	Selida.skiserService('metavoles', 'id=' + Client.feredataId).
	done(function(rsp) {
		var data;

		switch (rsp) {
		case '=':
			skiniko.metavoles();
			return;
		case '~':
			return;
		case '-':
			self.location = Selida.server + 'error?minima=' +
				('Διαπιστώθηκαν πολλαπλές συνεδρίες για τον χρήστη ' + Selida.session.pektis).uri();
			return;
		case '?':
			skiniko.stisimo();
			return;
		}

		try {
			data = ('{' + rsp + '}').evalAsfales();
		} catch (e) {
			
			return skiniko.feredataError('Παρελήφθησαν λανθασμένες μεταβολές σκηνικών δεδομένων', rsp, 1000);
		}

		if (!data.hasOwnProperty('id'))
		return skiniko.feredataError('Παρελήφθησαν μεταβολές σκηνικών δεδομένων χωρίς id', rsp, 1000);

		if (data.id < Client.feredataId)
		return skiniko.feredataError('Παρελήφθησαν παρωχημένες μεταβολές σκηνικών δεδομένων');

		skiniko.processFeredataMetavoles(data);
	}).
	fail(function(err) {
		Selida.skiserFail(err);
		skiniko.feredataError('Σφάλμα ενημέρωσης σκηνικών δεδομένων', 1000);
	});

	return this;
};

Skiniko.prototype.processFeredataMetavoles = function(data) {
	var kinisi;

console.log('METAVOLES', data);
	if (!data.hasOwnProperty('kinisi')) {
		Selida.fyi.epano('Δεν παρελήφθη array κινήσεων. Δρομολογήθηκε φρεσκάρισμα σκηνικού');
		this.stisimo();
		return this;
	}

	kinisi = data.kinisi;
	for (i = 0; i < kinisi.length; i++) {
		this.skinikoKinisiProcess(kinisi[i]);
	}

	this.
	panelRefresh().
	metavoles();

	return this;
};

Skiniko.prototype.egoRefreshDOM = function() {
	var kafenio, trapezi;

	this.skinikoKinisiProcess(new Kinisi({
		idos: 'EK',
		data: {
			pektis: ego.login,
			kafenio: ego.kafenioGet(),
		},
	}));

	return this;
};

Skiniko.prototype.panelRefresh = function() {
	Arena.mpanel.bpanelRefresh();
	Arena.kpanel.bpanelRefresh();
	Arena.tpanel.bpanelRefresh();
	Arena.cpanel.bpanelRefresh();

	return this;
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

Sinedria.prototype.sinedriaGetDOM = function() {
	return this.DOM;
};

Sinedria.prototype.sinedriaCreateDOM = function() {
	if (this.hasOwnProperty('DOM'))
	return this;

	this.DOM = $('<div>');
	return this;
};

Sinedria.prototype.sinedriaRefreshDOM = function() {
	this.
	sinedriaGetDOM().
	empty().
	removeClass().
	addClass('thamonas').
	addClass(this.sinedriaSimetoxiGet() === 'ΘΕΑΤΗΣ' ? 'theatis' : 'pektis').
	append($('<div>').addClass('thamonasOnoma').text(this.sinedriaPektisGet()));

	return this;
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

Kafenio.prototype.kafenioGetDOM = function() {
	return this.DOM;
};

Kafenio.prototype.kafenioCreateDOM = function() {
	if (this.hasOwnProperty('DOM'))
	return this;

	this.DOM = $('<div>');
	return this;
};

Kafenio.prototype.kafenioRefreshDOM = function() {
	var kafenio = this, dom, onomasia, dimiourgos, prive;

	onomasia = this.kafenioOnomasiaGet();
	if (!onomasia)
	onomasia = this.kafenioKodikosGet();

	dimiourgos = this.kafenioDimiourgosGet();
	prive = this.kafenioIsPrive();

	dom = this.kafenioGetDOM();

	dom.
	empty().
	removeClass().
	addClass('kafenio').
	append($('<div>').addClass('kafenioOnomasia').text(onomasia)).
	append($('<div>').addClass('kafenioOwner').text(dimiourgos)).
	on('mouseenter', function() {
		var desc;

		desc = 'καφενείο <span class="entona prasino">' + onomasia +
			'</span>, by <span class="entona prasino">' + dimiourgos + '</span>';

		if (prive)
		desc += ' (<span class="kokino">πριβέ</span>)';

		Selida.fyi.kato(desc, 0);
	}).
	on('mouseleave', function() {
		Selida.fyi.kato();
	}).
	on('click', function(e) {
		kafenio.kafenioEpilogi(e);
	});

	if (this.kafenioIsPrive()) {
		dom.addClass('kafenioPrive');
		if (this.kafenioOxiDiapiste(ego.login))
		dom.addClass('kafenioAvato');
	}

	if (ego.isKafenio(this))
	dom.addClass('kafenioTrexon');

	return this;
};

Kafenio.prototype.kafenioEpilogi = function(e) {
	Selida.skiserService('kafenioEpilogi', 'kafenio=' + this.kafenioKodikosGet()).
	done(function(rsp) {
		Selida.fyi.epano(rsp);
	}).
	fail(function(err) {
		Selida.skiserFail(err);
	});
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

ego = {
	login: null,
	pektis: null,
	sinedria: null,
};

ego.kafenioGet = function() {
	if (!ego.sinedria)
	return null;

	return ego.sinedria.sinedriaKafenioGet();
};

ego.isVip = function() {
	if (!ego.pektis)
	return false;

	return ego.pektis.pektisIsVip();
};

ego.isKafenio = function(kafenio) {
	var egoKafenio;

	egoKafenio = ego.kafenioGet();
	if (!egoKafenio)
	return false;

	if (typeof kafenio === 'object')
	kafenio = kafenio.kafenioKodikosGet();

	return egoKafenio == kafenio;
};

String.prototype.isEgo = function() {
	return(this.valueOf() === ego.login);
};

String.prototype.oxiEgo = function() {
	return !this.isEgo();
};
